package ranab.server.ftp;

import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;

/**
 * We can get the ftp data connection using this class.
 * It uses either PORT or PASV command.
 * 
 * @author <a href="mailto:rana_b@yahoo.com">Rana Bhattacharyya</a>
 */
class FtpDataConnection {
    
    private FtpConfig    mConfig  = null;
    private Socket       mDataSoc = null;
    private ServerSocket mServSoc = null;
    private InetAddress  mAddress = null;
    private int          miPort   = 0;
    
    private boolean mbPort  = false;
    private boolean mbPasv  = false;
    
    
    /**
     * Constructor.
     * @param cfg ftp config object.
     */
    public FtpDataConnection(FtpConfig cfg) {
        mConfig = cfg;
    }
    
    /**
     * Reset all the member variables. Close all sockets.
     */
    public void reset() {
        
        // close data socket
        if(mDataSoc != null) {
            try { 
                mDataSoc.close(); 
            } 
            catch(Exception ex) {
                mConfig.getLogger().warn(ex);
            }
            mDataSoc = null;
        }
        
        // close server socket
        if(mServSoc != null) {
            try { 
                mServSoc.close(); 
            } 
            catch(Exception ex) {
                mConfig.getLogger().warn(ex);
            }
            mServSoc = null;
        }
        
        // reset other variables
        mAddress = null;
        miPort   = 0;
        
        mbPort   = false;
        mbPasv   = false;
    }
     
     
    /**
     * Port command.
     */
    public void setPortCommand(InetAddress addr, int port) {
        reset();
        mbPort = true;
        mAddress = addr;
        miPort = port;
    } 
    
    /**
     * Passive command. It returns the success flag.
     */
    public boolean setPasvCommand() {
        boolean bRet = false;
        try {
          reset();
          mAddress = mConfig.getSelfAddress();
          mServSoc = new ServerSocket(0, 1, mAddress);
          mServSoc.setSoTimeout(600000);
          miPort = mServSoc.getLocalPort();
          mbPasv = true;
          bRet = true;
        }
        catch(Exception ex) {
            mConfig.getLogger().warn(ex);
        }
        return bRet;
    }
    
    /**
     * Listen for passive socket connection. It returns the success flag.
     */
    public boolean listenPasvConnection() {
        boolean bRet = false;
        mDataSoc = null;
        try {
            mDataSoc = mServSoc.accept();
            mDataSoc.setSoTimeout(600000);
            bRet = true;
        }
        catch(Exception ex) {
            mConfig.getLogger().warn(ex);
        }
        return bRet;
    }
     
     
    /**
     * Get client address.
     */
    public InetAddress getInetAddress() {
        return mAddress;
    }
     
    /**
     * Get port number.
     */
    public int getPort() {
        return miPort;
    }
     
    /**
     * Get the data socket. In case of error returns null.
     */
    public Socket getDataSocket() {
       
        // get socket depending on the selection
        if(mbPort) {
            try {
                mDataSoc = new Socket(mAddress, miPort); 
                mDataSoc.setSoTimeout(600000);                  
            }
            catch(Exception ex) {
                mConfig.getLogger().warn(ex);
                mDataSoc = null;
            }
        }
        else if(!mbPasv) {
            if (mDataSoc != null) {
                try { 
                    mDataSoc.close(); 
                } 
                catch(Exception ex) {
                    mConfig.getLogger().warn(ex);
                }
                mDataSoc = null;
            }
        }
        
        // result check
        return mDataSoc;
    }
    
    /**
     * Last defense - close connections.
     */
    protected void finalize() throws Throwable {
        reset();
        super.finalize();
    } 
}
    
